iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0
JavaScript

可愛又迷人的 Web API系列 第 28

Day28. 使用 Web Animations API 製作打散文字的動畫效果

  • 分享至 

  • xImage
  •  

這篇文章,想跟大家分享用滑鼠互動的動畫效果,這是一個滑鼠移入後,會將文字打散,滑鼠移出後會還原文字的動畫效果,以下是範例:

https://mukiwu.github.io/web-api-demo/img/27-3.gif

製作打散文字的動畫效果

首先在 html 寫好文字內容

<div id="text-container">
  你好,我是 MUKI,很高興認識你,Nice to meet you.
</div>

1. 選取文字容器並取得內容

先取得 HTML 中的文字元素,接下來,將 textContainerinnerHTML 設置為空字串,清除原有的內容。這一步是為了之後將每個字元包在 span 標籤中,為了獨立控制每個字元的動畫效果。

const textContainer = document.getElementById('text-container');
const textContent = textContainer.textContent;
textContainer.innerHTML = '';

2. 將每個字元包在 span 標籤中

textContent.split('').forEach(char => {
  if (char === ' ') {
    textContainer.appendChild(document.createTextNode(' '));
  } else {
    const span = document.createElement('span');
    span.className = 'char';
    span.textContent = char;
    textContainer.appendChild(span);
  }
});

textContent 分解為獨立字元後,先檢查這些字元是否為空白字元,如果是空白字元,就加入一個空白的 TextNodetextContainer,因為我的原文有空格,這樣做是為了保留原文中的空白字元。

對於非空白字元,就將每個字元單獨包在 span 標籤裡,為了可以分開控制每個字元的動畫效果。

3. 滑鼠移入後,將文字打散

使用 mouseenter 事件監聽器,透過 forEach 迴圈,對每個字元進行處理。

因為我希望每次滑鼠移入後,打散的位置都是隨機的,所以用 Math.random() 產生隨機的 X 軸和 Y 軸,以及隨機的旋轉角度。最後用到 animate() 方法,設定開始跟結束的位移與旋轉角度,特別注意的是動畫結束後,這些元素會保持在動畫的終止狀態 (fill: 'forwards'),不要讓他回到起點唷

textContainer.addEventListener('mouseenter', () => {
  chars.forEach(char => {
    const randomX = (Math.random() - 0.5) * 300;
    const randomY = (Math.random() - 0.5) * 300;
    const randomRotation = Math.random() * 360;

    char.animate([
      { transform: 'translate(0, 0) rotate(0deg)' },
      { transform: `translate(${randomX}px, ${randomY}px) rotate(${randomRotation}deg)` }
    ], {
      duration: 1000,
      fill: 'forwards'
    });
  });
});

4. 滑鼠移出後,文字會回到原來的位置

使用 mouseleave 事件監聽器,將起始與終止的位置顛倒,就能讓文字恢復正常了。

通常會建議紀錄滑鼠移入後,文字的終止位置,再把他當成滑鼠移出時文字的起始位置,但我覺得都是亂數的效果也不錯,在這個範例就沒有那麼講究了。

textContainer.addEventListener('mouseleave', () => {
  chars.forEach(char => {
    const randomX = (Math.random() - 0.5) * 300;
    const randomY = (Math.random() - 0.5) * 300;
    const randomRotation = Math.random() * 360;
        
    char.animate([
      { transform: `translate(${randomX}px, ${randomY}px) rotate(${randomRotation}deg)` },
      { transform: 'translate(0, 0) rotate(0deg)' }
    ], {
      duration: 1000,
      fill: 'forwards'
    });
  });
});

完整程式碼

大家有興趣的話,可以再將這個程式碼修改成你喜歡的樣子

const textContainer = document.getElementById('text-container');
const textContent = textContainer.textContent;
textContainer.innerHTML = '';

textContent.split('').forEach(char => {
  if (char === ' ') {
    textContainer.appendChild(document.createTextNode(' '));
  } else {
    const span = document.createElement('span');
    span.className = 'char';
    span.textContent = char;
    textContainer.appendChild(span);
  }
});

const chars = document.querySelectorAll('.char');

textContainer.addEventListener('mouseenter', () => {
  chars.forEach(char => {
    const randomX = (Math.random() - 0.5) * 300;
    const randomY = (Math.random() - 0.5) * 300;
    const randomRotation = Math.random() * 360;

    char.animate([
      { transform: 'translate(0, 0) rotate(0deg)' },
      { transform: `translate(${randomX}px, ${randomY}px) rotate(${randomRotation}deg)` }
    ], {
      duration: 1000,
      fill: 'forwards'
    });
  });
});

textContainer.addEventListener('mouseleave', () => {
  chars.forEach(char => {
    const randomX = (Math.random() - 0.5) * 300;
    const randomY = (Math.random() - 0.5) * 300;
    const randomRotation = Math.random() * 360;
    
    char.animate([
      { transform: `translate(${randomX}px, ${randomY}px) rotate(${randomRotation}deg)` },
      { transform: 'translate(0, 0) rotate(0deg)' }
    ], {
      duration: 1000,
      fill: 'forwards'
    });
  });
});

範例程式碼

範例程式碼:https://mukiwu.github.io/web-api-demo/animation.html

小結

以上有任何問題,都歡迎留言討論。


上一篇
Day27. 使用 JavaScript 操作動畫的 Web Animations API
下一篇
Day29. 使用 Screen Capture API 取得你的螢幕畫面
系列文
可愛又迷人的 Web API31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言